﻿Imports iConverter.Models
Imports iConverter.Core
Imports System.ComponentModel
Imports iConverter.Configuration
Imports System.Collections.ObjectModel
Imports System.Text
Imports iConverter.Extensions


Namespace ViewModels

    ''' <summary>
    ''' OptionWindow 窗口的 ViewModel
    ''' </summary>
    ''' <remarks>用于OptionWindow的 ViewModel ，包含 逻辑规则</remarks>
    Public Class OptionViewModel
        Implements INotifyPropertyChanged, IDisposable


#Region "INotifyPropertyChanged 的实现 "

        ''' <summary>
        ''' 用来引发 PropertyChanged 事件，当属性被更改之后
        ''' </summary>
        ''' <param name="propName">属性名字</param>
        Private Sub Notify(ByVal propName As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))
        End Sub

        Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

#End Region



#Region "IDisposable Support"
        Private disposedValue As Boolean ' 检测冗余的调用

        ' IDisposable
        Protected Overridable Sub Dispose(disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    '  释放托管状态(托管对象)。

                    Me._encodingList.Clear()

                End If

                '  释放非托管资源(非托管对象)并重写下面的 Finalize()。
                '  将大型字段设置为 null。

                Me._encodingList = Nothing
                Me._settings.EncodingList = Nothing
                Me._win = Nothing

            End If
            Me.disposedValue = True
        End Sub

        ' 仅当上面的 Dispose(ByVal disposing As Boolean)具有释放非托管资源的代码时重写 Finalize()。
        'Protected Overrides Sub Finalize()
        '    ' 不要更改此代码。请将清理代码放入上面的 Dispose(ByVal disposing As Boolean)中。
        '    Dispose(False)
        '    MyBase.Finalize()
        'End Sub

        ' Visual Basic 添加此代码是为了正确实现可处置模式。
        Public Sub Dispose() Implements IDisposable.Dispose
            ' 不要更改此代码。请将清理代码放入上面的 Dispose(ByVal disposing As Boolean)中。
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

        ''' <summary>
        '''应用此ViewModel的窗体
        ''' </summary>
        ''' <remarks></remarks>
        Dim _win As Window

        Public Sub New(ByVal win As Window)
            _isAskClosing = True
            _settings = SettingManager.Settings.Clone

            AddHandler _settings.PropertyChanged, AddressOf Me.SettingChanged

            CreateEncodingList()

            _checkedEncodingCount = GetCheckedEncodingCount()

            Me._win = win
            win.DataContext = Me

            RegisterCommandBindings()

            RegisterWindowsEvent()

        End Sub

        ' ''' <summary>
        ' ''' 析构
        ' ''' </summary>
        ' ''' <remarks></remarks>
        'Protected Overrides Sub Finalize()
        '    MyBase.Finalize()
        'End Sub

        ''' <summary>
        ''' 关闭窗体并卸载实例
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub Close(Optional isSkipWindow As Boolean = False)
            Me._isAskClosing = False
            Me.RemoveSettingsChangedHandler()
            UnRegisterWindowsEvent()
            If Not isSkipWindow Then Me._win.Close()
            Me.Dispose()
        End Sub



        ''' <summary>
        ''' 更新设置修改
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub Update()
            Me.UpdateEncodingList()
            Me.UpdateUsePluginPostProcessings()
            Me.UpdatePluginProviders()


        End Sub





#Region "检测 设置是否修改"

        ''' <summary>
        ''' 一个值，用来指示在关闭窗体时，是否询问继续关闭
        ''' </summary>
        ''' <remarks></remarks>
        Private _isAskClosing As Boolean

        ''' <summary>
        ''' 一个值，用来指示是否更改过设置
        ''' </summary>
        ''' <remarks></remarks>
        Private _isChanged As Boolean

        ''' <summary>
        ''' 已选择的编码数量
        ''' </summary>
        ''' <remarks>默认的</remarks>
        Private _checkedEncodingCount As Integer



        ''' <summary>
        ''' 指示是否更改过设置
        ''' </summary>
        ''' <remarks></remarks>
        Public ReadOnly Property IsChanged() As Boolean
            Get
                Return _isChanged OrElse Me._checkedEncodingCount <> GetCheckedEncodingCount()
            End Get
        End Property


        ''' <summary>
        ''' 获取已选择的编码数量
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function GetCheckedEncodingCount() As Integer
            Return Me.EncodingList.AsParallel.Count(Function(x) (x.IsChecked))
        End Function

        ''' <summary>
        ''' 设置修改事件
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub SettingChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs)
            If Not Me._isChanged Then
                Me._isChanged = True
            End If
        End Sub


        ''' <summary>
        ''' 移除 Setting 事件注册
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub RemoveSettingsChangedHandler()
            RemoveHandler _settings.PropertyChanged, AddressOf Me.SettingChanged
        End Sub


#End Region

        ''' <summary>
        ''' 当前设置
        ''' </summary>
        ''' <remarks></remarks>
        Private _settings As SettingInfo

        ''' <summary>
        ''' 当前设置
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property CurrentSettings() As SettingInfo
            Get
                Return _settings
            End Get
        End Property



#Region "编码列表"



        Private _encodingList As ObservableCollection(Of CheckableItem(Of Encoding))



        ''' <summary>
        ''' 获取编码列表
        ''' </summary>
        ''' <value> </value>
        ''' <returns> </returns>
        ''' <remarks> </remarks>
        Public ReadOnly Property EncodingList As ObservableCollection(Of CheckableItem(Of Encoding))
            Get
                If Me._encodingList Is Nothing Then
                    CreateEncodingList()
                End If
                Return _encodingList
            End Get
        End Property


        ''' <summary>
        ''' 创建编码列表
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub CreateEncodingList()

            Dim list As New List(Of CheckableItem(Of Encoding))


            '添加默认项目
            '添加系统编码

            list.Add(CheckableItem(Of Encoding).CreateCanNotCheck(EncodingManager.DefaultEncoding))

            '添加 Unicode编码
            Dim checkunicodes = EncodingManager.UnicodeEncodingList.Select(Function(item) (CheckableItem(Of Encoding).CreateCanNotCheck(item)))

            list.AddRange(checkunicodes)

            list.Add(CheckableItem(Of Encoding).CreateCanNotCheck(EncodingManager.UTF7))

            '添加其他编码
            Dim checkencodings = Me.CurrentSettings.EncodingList.Select(Function(x) (CheckableItem(Of Encoding).CreateCanCheck(x, True)))

            list.AddRange(checkencodings)

            '剩余编码

            'Dim lastencoding = From e In EncodingManager.AllEncodings
            '                   Where Not e.Equals(EncodingManager.DefaultEncoding)

            Dim lastencoding = EncodingManager.AllEncodings.Where(Function(e)
                                                                      If e.Equals(EncodingManager.DefaultEncoding) OrElse
                                                                         e.Equals(EncodingManager.UTF7) OrElse
                                                                         e.IsUnicodeEncoding OrElse
                                                                         Me.CurrentSettings.EncodingList.Contains(e) Then
                                                                          Return False
                                                                      End If

                                                                      Return True
                                                                  End Function).Select(Function(x) (CheckableItem(Of Encoding).CreateCanCheck(x))).OrderBy(Function(x) (x.Item.EncodingName))

            list.AddRange(lastencoding)

            Dim orderlist = list


            '更改显示顺序

            _encodingList = New ObservableCollection(Of CheckableItem(Of Encoding))

            For Each item In orderlist
                _encodingList.Add(item)
            Next



        End Sub

        ''' <summary>
        ''' 更新编码列表到当前设置里
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub UpdateEncodingList()
            Dim list = From item In Me.EncodingList
                       Where item.CanCheck AndAlso item.IsChecked
                       Select item.Item

            Me.CurrentSettings.EncodingList.Clear()
            Me.CurrentSettings.EncodingList.AddRange(list)

        End Sub



#End Region



        ''' <summary>
        ''' 表示可以选择的项目
        ''' </summary>
        ''' <typeparam name="T">用于承载内容的类型</typeparam>
        ''' <remarks></remarks>
        Public Class CheckableItem(Of T)
            Implements INotifyPropertyChanged


#Region "INotifyPropertyChanged 的实现 "

            ''' <summary>
            ''' 用来引发 PropertyChanged 事件，当属性被更改之后
            ''' </summary>
            ''' <param name="propName">属性名字</param>
            Private Sub Notify(ByVal propName As String)
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))
            End Sub

            Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

#End Region


            ''' <summary>
            ''' 创建对象新的实例
            ''' </summary>
            ''' <param name="item">要承载的内容</param>
            ''' <remarks></remarks>
            Public Sub New(ByVal item As T)
                MyClass.New(item, True)
            End Sub
            ''' <summary>
            ''' 创建对象新的实例
            ''' </summary>
            ''' <param name="item">要承载的内容</param>
            ''' <param name="CanCheck">一个值用来指示否是可以选择</param>
            ''' <remarks></remarks>
            Public Sub New(ByVal item As T, ByVal CanCheck As Boolean)
                MyClass.New(item, CanCheck, False)
            End Sub
            ''' <summary>
            ''' 创建对象新的实例
            ''' </summary>
            ''' <param name="item">要承载的内容</param>
            ''' <param name="CanCheck">一个值用来指示否是可以选择</param>
            ''' <param name="isChecked">一个值用来指示项目是否被选择</param>
            ''' <remarks></remarks>
            Public Sub New(item As T, CanCheck As Boolean, isChecked As Boolean)
                Me._Item = item
                Me._CanCheck = CanCheck
                Me._IsChecked = isChecked

            End Sub




            Private _Item As T
            ''' <summary>
            ''' 承载的内容
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Item As T
                Get
                    Return _Item
                End Get
                Set(value As T)
                    _Item = value
                    Notify("Item")
                End Set
            End Property


            ''' <summary>
            ''' 用来指示项目是否被选择
            ''' </summary>
            Private _IsChecked As Boolean
            ''' <summary>
            ''' 获取和设置一个值，用来指示项目是否被选择
            ''' </summary>
            ''' <value>用来指示项目是否被选择</value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property IsChecked As Boolean
                Get
                    Return _IsChecked
                End Get
                Set(value As Boolean)
                    _IsChecked = value
                    Notify("IsChecked")
                End Set
            End Property



            ''' <summary>
            ''' 用来指示项目是否可以选择
            ''' </summary>
            Private _CanCheck As Boolean

            ''' <summary>
            ''' 获取一个值，用来指示项目是否可以选择
            ''' </summary>
            ''' <value>用来指示项目是否可以选择</value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public ReadOnly Property CanCheck As Boolean
                Get
                    Return _CanCheck
                End Get
            End Property



            ''' <summary>
            ''' 使用指定的内容创建可选择项目的实例
            ''' </summary>
            ''' <param name="item">要承载的内容</param>
            ''' <param name="isChecked">可选，一个值用来指示项目是否被选择，默认 Flase</param>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Shared Function CreateCanCheck(item As T,
                                                  Optional isChecked As Boolean = False) As CheckableItem(Of T)
                Return New CheckableItem(Of T)(item, True, isChecked)
            End Function

            ''' <summary>
            ''' 使用指定的内容创建不可选的项目的实例
            ''' </summary>
            ''' <param name="item">要承载的内容</param>
            ''' <returns></returns>
            ''' <remarks>
            '''    CanCheck 为 False， isCheck 为 True的项目
            ''' </remarks>
            Public Shared Function CreateCanNotCheck(item As T) As CheckableItem(Of T)
                Return New CheckableItem(Of T)(item, False, True)
            End Function

        End Class



#Region "插件列表 "


        ''' <summary>
        ''' 插件提供器集合 
        ''' </summary>
        ''' <remarks></remarks>
        Private _PluginProviders As ObservableCollection(Of PluginProvider)


        ''' <summary>
        ''' 插件提供器集合 
        ''' </summary>
        ''' <remarks></remarks>
        Public ReadOnly Property PluginProviders() As ObservableCollection(Of PluginProvider)
            Get
                If Me._PluginProviders Is Nothing Then
                    CreatePluginProvidersList()
                End If
                Return _PluginProviders
            End Get
        End Property

        ''' <summary>
        ''' 创建插件提供列表
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub CreatePluginProvidersList()

            Dim providers = PluginsManager.Providers

            Me._PluginProviders = New ObservableCollection(Of PluginProvider)(providers)


        End Sub



        ''' <summary>
        ''' 处理 插件 提供器 禁用和开启
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub UpdatePluginProviders()
            Dim dproviders = PluginsManager.Providers.Where(Function(x) Not x.IsEnabled)

            For Each p In dproviders
                Me.CurrentSettings.DisabledPluginProviders.Add(p)
            Next


        End Sub
#End Region



#Region "后期处理插件相关"



        ''' <summary>
        ''' 插件提供器集合 
        ''' </summary>
        ''' <remarks></remarks>
        Private _PluginPostProcessings As ObservableCollection(Of CheckableItem(Of PostProcessing))


        ''' <summary>
        ''' 插件提供器集合 
        ''' </summary>
        ''' <remarks></remarks>
        Public ReadOnly Property PluginPostProcessings() As ObservableCollection(Of CheckableItem(Of PostProcessing))
            Get
                If Me._PluginPostProcessings Is Nothing Then
                    CreatePluginPostProcessingsList()
                End If
                Return _PluginPostProcessings
            End Get
        End Property

        ''' <summary>
        ''' 创建后期处理插件列表
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub CreatePluginPostProcessingsList()
            Dim list = From pp In PluginsManager.PostProcessings
                       Select New CheckableItem(Of PostProcessing)(pp)


            '  Dim list1, list2 As New List(Of CheckableItem(Of PostProcessing))

            Dim datas = list.ToList

            For Each i In datas
                Dim item = i.Item

                Dim ishas = item.Processings.Any(Function(x) (x.isSelected))

                If Not ishas Then
                    Dim f = item.Processings.FirstOrDefault

                    If f IsNot Nothing Then
                        f.isSelected = True
                    End If
                Else
                    i.IsChecked = True
                End If


            Next

            'For Each item In Me.CurrentSettings.UsePostProcessings
            '    Dim ppid = item.PostProcessingID
            '    Dim t = datas.FirstOrDefault(Function(x) (x.Item.ID = ppid))
            '    If t IsNot Nothing Then
            '        list1.Add(t)

            '    End If
            'Next

            'Dim last = datas.Except(list1)

            'list2.AddRange(list1)
            'list2.AddRange(last)


            ' Dim ppps As New ObservableCollection(Of CheckableItem(Of PostProcessing))(list2)


            Dim ppps As New ObservableCollection(Of CheckableItem(Of PostProcessing))(datas)



            Me._PluginPostProcessings = ppps

        End Sub
#End Region

        ''' <summary>
        ''' 更新使用后期处理插件 列表
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub UpdateUsePluginPostProcessings()

            Dim upps = Me.CurrentSettings.UsePostProcessings

            upps.Clear()


            Dim selecteds = From pp In Me._PluginPostProcessings
                           Where pp.IsChecked
                           Select pp.Item



            For Each pp In selecteds


                For Each p In pp.Processings
                    If p.isSelected Then
                        upps.Add(pp.Provider.ID, pp.ID, p.ID)
                        Exit For
                    End If
                Next

            Next

            Me.CurrentSettings.UsePostProcessings = upps

        End Sub






    End Class

End Namespace


